`timescale 1ns / 1ps
/*
 Copyright 2020 Sean Xiao, jxzsxsp@qq.com
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

module csr_reg
(
    input sys_clk,

    input i_mret_ena,

    input [ 31: 0 ] i_dcsr,
    input [ 31: 0 ] i_dpc,
    input [ 31: 0 ] i_dscratch,

    output o_wr_dcsr_ena,
    output o_wr_dpc_ena,
    output o_wr_dscrh_ena,

    input i_dbg_mode,
    input i_dbg_stpcyl,
    input i_EXE_vld,

    input i_ext_irq,
    input i_sft_irq,
    input i_tmr_irq,

    input i_irq_src,
    input i_exp_src,
    input [ 31: 0 ] i_exe_pc,
    input [ 31: 0 ] i_ir,

    output [ 31: 0 ] o_mepc,
    output [ 31: 0 ] o_irq_pc,

    input i_csr_rden,
    input [ 11: 0 ] i_csr_addr,
    input [ 31: 0 ] i_csr_val,
    input i_csr_wen,
    output [ 31: 0 ] o_csr_val,

    output o_meie,
    output o_msie,
    output o_mtie,
    output o_glb_irq,

    input rst_n
);

//===============================================================================

wire acc_dis = 1'b0;
reg  [ 31: 0 ] csr_reh_sel;
wire [ 31: 0 ] w_mtvec;
wire [ 31: 0 ] w_mstatus;
wire [ 31: 0 ] w_misa;
wire [ 31: 0 ] w_mie;
wire [ 31: 0 ] w_mcounteren;
wire [ 31: 0 ] w_mvendorid;
wire [ 31: 0 ] w_marchid;
wire [ 31: 0 ] w_mimpid;
wire [ 31: 0 ] w_mhartid;
wire [ 31: 0 ] w_mscratch;
wire [ 31: 0 ] w_mcause;
wire [ 31: 0 ] w_mtval;
wire [ 31: 0 ] w_mip;

wire [ 31: 0 ] w_mcycle_h;
wire [ 31: 0 ] w_mcycle_l;

wire [ 31: 0 ] w_minstret_h;
wire [ 31: 0 ] w_minstret_l;

assign o_glb_irq = w_mstatus[3];
//===============================================================================
assign o_csr_val = csr_reh_sel;

always@( * )   //csr read
case ( i_csr_addr & { 12{ i_csr_rden } } )
    12'h300: csr_reh_sel <= w_mstatus;
    12'h301: csr_reh_sel <= w_misa;
    12'h304: csr_reh_sel <= w_mie;
    12'h305: csr_reh_sel <= w_mtvec;
    12'h306: csr_reh_sel <= w_mcounteren;
    12'hf11: csr_reh_sel <= w_mvendorid;
    12'hf12: csr_reh_sel <= w_marchid;
    12'hf13: csr_reh_sel <= w_mimpid;
    12'hf14: csr_reh_sel <= w_mhartid;
    12'h340: csr_reh_sel <= w_mscratch;
    12'h341: csr_reh_sel <= o_mepc;
    12'h342: csr_reh_sel <= w_mcause;
    12'h343: csr_reh_sel <= w_mtval;
    12'h344: csr_reh_sel <= w_mip;
    12'hb00: csr_reh_sel <= w_mcycle_l;
    12'hb80: csr_reh_sel <= w_mcycle_h;
    12'hb02: csr_reh_sel <= w_minstret_l;
    12'hb82: csr_reh_sel <= w_minstret_h;
    12'h7b0: csr_reh_sel <= i_dcsr;
    12'h7b1: csr_reh_sel <= i_dpc;
    12'h7b2: csr_reh_sel <= i_dscratch;
    default: csr_reh_sel <= 32'b0;
endcase

wire [ 31: 0 ] vect_pc = w_mtvec[ 31: 0 ] + {w_mcause[ 3: 0 ], 2'b00};  // execption X4 address

assign o_irq_pc = ( w_mtvec[ 1: 0 ] == 0 ) ? w_mtvec :
                  ( w_mtvec[ 1 :0 ] == 1 ) ? vect_pc : o_irq_pc;

wire status_ena = w_mstatus[3] & ( o_meie | o_mtie | o_msie ) & i_irq_src;

//===============================================================================
// WPRI : Reserved Writes Preserve Values, Reads Ignore Values
// WLRL : Write/Read Only Legal Values
// WARL : Write Any Values, Reads Legal Values
// WPRI : Reserved Writes Preserve Values, Reads Ignore Values
// WIRI : reserved Writes Ignored, Reads Ignore Values
//===============================================================================
csr_mtvec csr_mtvec_u
(
    .sys_clk    ( sys_clk ),

    .i_acc_dis  ( acc_dis ),
    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .o_mtvec    ( w_mtvec ),

    .rst_n      ( rst_n )
);

//===============================================================================
csr_mstatus csr_mstatus_u
(
    .sys_clk        ( sys_clk ),

    .i_mret_ena     ( i_mret_ena ),
    .i_status_ena   ( status_ena ),

    .i_acc_dis      ( acc_dis ),
    .i_csr_addr     ( i_csr_addr ),
    .i_csr_val      ( i_csr_val ),
    .i_csr_wen      ( i_csr_wen ),

    .o_mstatus      ( w_mstatus ),

    .rst_n          ( rst_n )
);
//===============================================================================
csr_mtval csr_mtval_u
(
    .sys_clk    ( sys_clk ),

    .i_irq_src  ( i_irq_src ),
    .i_exp_src  ( i_exp_src ),
    .i_exe_pc   ( i_exe_pc ),
    .i_ir       ( i_ir ),

    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .o_mtval    ( w_mtval ),
    
    .rst_n      ( rst_n )

);
//===============================================================================
csr_mepc csr_mepc_u
(
    .sys_clk    ( sys_clk ),


    .i_irq_src  ( i_irq_src ),
    .i_exp_src  ( i_exp_src ),
    .i_exe_pc   ( i_exe_pc ),

    .i_acc_dis  ( acc_dis ),
    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .o_mepc     ( o_mepc ),

    .rst_n      ( rst_n )
);
//===============================================================================
csr_mcause csr_mcause_u
(
    .sys_clk    ( sys_clk ),

    .i_irq_src  ( i_irq_src ),
    .i_exp_src  ( i_exp_src ),
    .i_mie      ( w_mstatus[7] | w_mstatus[3] ),   //w_mie

    .i_meie     ( o_meie ),
    .i_mtie     ( o_mtie ),
    .i_msie     ( o_msie ),

    .i_sft_irq  ( i_sft_irq ),
    .i_tmr_irq  ( i_tmr_irq ),
    .i_ext_irq  ( i_ext_irq ),

    .i_EXE_vld  ( i_EXE_vld ),
    .i_acc_dis  ( acc_dis ),
    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .i_iam_exp  ( 1'b0 ),
    .i_iaf_exp  ( 1'b0 ),
    .i_illi_exp ( 1'b0 ),
    .i_bp_exp   ( 1'b0 ),
    .i_mti_exp  ( 1'b0 ),
    .i_lam_exp  ( 1'b0 ),
    .i_laf_exp  ( 1'b0 ),
    .i_saam_exp ( 1'b0 ),
    .i_saaf_exp ( 1'b0 ),

    .o_mcause   ( w_mcause ),

    .rst_n      ( rst_n )
);
//===============================================================================
csr_mie csr_mie_u
(
    .sys_clk    ( sys_clk ),

    .i_acc_dis  ( acc_dis ),
    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .o_mie      ( w_mie ),
    .o_meie     ( o_meie ),
    .o_msie     ( o_msie ),
    .o_mtie     ( o_mtie ),

    .rst_n      ( rst_n )
);
//===============================================================================
csr_mip csr_mip_u
(
    .sys_clk    ( sys_clk ),

    .i_sft_irq  ( i_sft_irq ),
    .i_tmr_irq  ( i_tmr_irq ),
    .i_ext_irq  ( i_ext_irq ),

    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .o_mip      ( w_mip ),

    .rst_n      ( rst_n )
);
//===============================================================================

csr_misa csr_misa_u
(
    .i_csr_addr ( i_csr_addr ),
    .o_misa     ( w_misa )
);

//===============================================================================
csr_mcounteren csr_mcounteren_u
(
    .sys_clk        ( sys_clk ),

    .i_csr_addr     ( i_csr_addr ),
    .i_csr_val      ( i_csr_val ),
    .i_csr_wen      ( i_csr_wen ),

    .o_mcounteren   ( w_mcounteren ),

    .rst_n          ( rst_n )
);

//===============================================================================
csr_mid csr_mid_u
(
    .i_csr_addr ( i_csr_addr ),
    .o_mvendorid( w_mvendorid ),
    .o_marchid  ( w_marchid ),
    .o_mimpid   ( w_mimpid ),
    .o_mhartid  ( w_mhartid )
);

//===============================================================================
csr_scratch csr_scratch_u
(
    .sys_clk    ( sys_clk ),

    .i_csr_addr ( i_csr_addr ),
    .i_csr_val  ( i_csr_val ),
    .i_csr_wen  ( i_csr_wen ),

    .o_mscratch ( w_mscratch ),

    .rst_n      ( rst_n )
);
//===============================================================================

csr_mcycle csr_mcycle_u
(
    .sys_clk        ( sys_clk ),

    .i_dbg_mode     ( i_dbg_mode ),
    .i_dbg_stpcyl   ( i_dbg_stpcyl ),

    .i_csr_addr     ( i_csr_addr ),
    .i_csr_val      ( i_csr_val ),
    .i_csr_wen      ( i_csr_wen ),

    .o_mcycle_l     ( w_mcycle_l ),
    .o_mcycle_h     ( w_mcycle_h ),

    .rst_n          ( rst_n )
);
//===============================================================================

csr_minstret csr_minstret_u
(
    .sys_clk        ( sys_clk ),

    .i_EXE_vld      ( i_EXE_vld ),
    .i_dbg_mode     ( i_dbg_mode ),
    .i_dbg_stpcyl   ( i_dbg_stpcyl ),

    .i_csr_addr     ( i_csr_addr ),
    .i_csr_val      ( i_csr_val ),
    .i_csr_wen      ( i_csr_wen ),

    .o_minstret_l   ( w_minstret_l ),
    .o_minstret_h   ( w_minstret_h ),

    .rst_n          ( rst_n )
);
//===============================================================================
dug_csr deg_csr_u
(
    .sys_clk        ( sys_clk ),

    .i_csr_addr     ( i_csr_addr ),
    .i_csr_wen      ( i_csr_wen ),

    .o_wr_dcsr_ena  ( o_wr_dcsr_ena ),
    .o_wr_dpc_ena   ( o_wr_dpc_ena ),
    .o_wr_dscrh_ena ( o_wr_dscrh_ena ),

    .rst_n          ( rst_n )
);
//===============================================================================
endmodule
